package com.atguigu.jinx.service.impl;


import com.atguigu.jinx.conf.WxPayConfig;
import com.atguigu.jinx.entity.dto.RechargeRequest;
import com.atguigu.jinx.entity.pojo.QueryVo;
import com.atguigu.jinx.enums.ProcessStatus;
import com.atguigu.jinx.enums.alipay.AlipayErrorCode;
import com.atguigu.jinx.enums.alipay.AlipayOrderStatusEnum;
import com.atguigu.jinx.enums.alipay.TradeErrorCode;
import com.atguigu.jinx.enums.wxpay.WxApiType;
import com.atguigu.jinx.exception.BusinessException;
import com.atguigu.jinx.mapper.RechargeRequestMapper;
import com.atguigu.jinx.service.IRechargeRequestService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.gson.Gson;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.Objects;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author steve
 * @since 2025-08-27
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class RechargeRequestServiceImpl extends ServiceImpl<RechargeRequestMapper, RechargeRequest> implements IRechargeRequestService {


    private final AlipayTemplate alipayTemplate;

    private final Gson gson;

    private final WxPayConfig wxPayConfig;

    private final CloseableHttpClient httpClient;


    /**
     * 查单 修改充值订单的最终状态 (该方法既可以进行是手动查单,也可以延迟支付查单)
     *
     * @param orderNo 订单号
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void changeRechargeOrderSyncStatusFromAlipay(String orderNo) {
        // 1. 获取订单并校验
        RechargeRequest request = getRechargeRequest(orderNo);

        // 2. 仅在处理中才需要查询支付宝  (设置一个不搞的状态 这样比包围一个长的if简短很多)
        if (request.getStatus() != ProcessStatus.PROCESSING.getCode()) {
            // 该订单说不定已经支付成功了
            log.info("订单[{}]状态非处理中，当前状态为[{}]，无需同步", orderNo, request.getStatus());
            return;
        }

        // 3. 构建请求参数
        QueryVo queryVo = buildQueryVo(request, orderNo);
        log.info("=====> 支付宝查单请求数据: {}", queryVo);

        // 4. 发起请求并解析响应
        Map<String, Object> responseResultMap = queryAlipay(queryVo);
        log.info("<===== 支付宝查单响应数据: {}", responseResultMap);

        // 5. 校验订单号一致性
        validateOrderNo(request, orderNo, responseResultMap);

        // 6. 更新订单状态
        updateRechargeOrderStatus(request, responseResultMap);
    }

    /**
     * 查单 修改充值订单的最终状态 (该方法既可以进行是手动查单,也可以延迟支付查单)
     *
     * @param orderNo 订单号
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void changeRechargeOrderSyncStatusFromWechatpay(String orderNo) throws IOException {
        // 1. 获取订单并校验
        RechargeRequest request = getRechargeRequest(orderNo);

        // 2.订单状态只有在申请中的时候才会去查询订单
        if (request.getStatus() != ProcessStatus.PROCESSING.getCode()) {
            // 该订单说不定已经支付成功了
            log.info("订单[{}]状态非处理中，当前状态为[{}]，无需同步", orderNo, request.getStatus());
            return;
        }

        // 3. 构建请求参数
        String url = wxPayConfig.getDomain().concat(String.format(WxApiType.ORDER_QUERY_BY_NO.getType(), orderNo)).concat("?mchid=").concat(wxPayConfig.getMchId());
        log.info("=====> 微信查单请求数据: {}", orderNo);
        HttpGet httpGet = new HttpGet(url);
        httpGet.setHeader("Accept", "application/json");

        try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
            int statusCode = response.getStatusLine().getStatusCode();
            String responseEntity = EntityUtils.toString(response.getEntity());
            /**
             * 状态确认
             */
            switch (statusCode) {
                case HttpStatus.SC_OK:
                    log.info("200响应成功:[{}]", responseEntity);
                    break;
                case HttpStatus.SC_NO_CONTENT:
                    log.info("204响应成功,无返回状态:");
                    break;
                default:
                    log.error("出错了,响应码:[{}],返回对象:[{}]", statusCode, responseEntity);
                    break;
            }

            // 4.拿到结果集
            Map resultMap = gson.fromJson(responseEntity, Map.class);

            // 判断正常还是异常的逻辑
            if (StringUtils.isNotBlank((CharSequence) resultMap.get("code"))) {
                // 出现异常

            }


        }
    }

    /**
     * 构建查询参数
     */
    private QueryVo buildQueryVo(RechargeRequest request, String orderNo) {
        QueryVo queryVo = new QueryVo();
        queryVo.setOut_trade_no(request.getOutOrderNo());
        queryVo.setTrade_no(orderNo);
        return queryVo;
    }

    private RechargeRequest getRechargeRequest(String orderNo) {
        // 获取到充值订单编号
        RechargeRequest request = getOne(new LambdaQueryWrapper<RechargeRequest>()
                .eq(RechargeRequest::getOrderNo, orderNo));
        // 判空
        if (Objects.isNull(request)) {
            log.error("该订单号哦所对应的订单不存在{}", orderNo);
            throw new BusinessException("该订单号所对应的订单不存在:" + orderNo);
        }
        Assert.notNull(request.getStatus(), "支付订单状态为空");
        return request;
    }

    /**
     * 请求支付宝查单并解析结果
     * suppresswarning的作用是压制住可能存在的异常
     */
    @SuppressWarnings("unchecked")
    private Map<String, Object> queryAlipay(QueryVo queryVo) {
        String responseJson = alipayTemplate.queryOrder(queryVo);
        Map<String, Object> map = gson.fromJson(responseJson, Map.class);
        return (Map<String, Object>) map.get("alipay_trade_query_response");
    }

    /**
     * 校验订单号一致性
     */
    private void validateOrderNo(RechargeRequest request, String orderNo, Map<String, Object> responseResultMap) {
        //API 公共错误码
        String publicResponseCode = (String) responseResultMap.get("code");

        // 10000 和 40004 作为 状态业务码,其余的业务码进行异常的抛出和log的打印
        if (!AlipayErrorCode.SUCCESS.getCode().equals(publicResponseCode) && !AlipayErrorCode.BUSINESS_FAILED.getCode().equals(publicResponseCode)) {
            log.error("支付宝查单参数返回其它异常结果{},异常类型为{},订单号{}", responseResultMap, AlipayErrorCode.getMessageFromCode(publicResponseCode), orderNo);
            throw new BusinessException("支付宝查单中出现异常");
        }

        String responseOrderNo = (String) responseResultMap.get("out_trade_no");
        if (!Objects.equals(request.getOutOrderNo(), responseOrderNo)) {
            log.error("订单号校验失败: localOutOrderNo={}, outOrderNo={}, orderNo={}",
                    request.getOutOrderNo(), responseOrderNo, orderNo);
            throw new BusinessException("订单号不一致");
        }
    }

    /**
     * 更新订单状态
     */
    private void updateRechargeOrderStatus(RechargeRequest request, Map<String, Object> responseResultMap) {
        // 公共校验码
        String code = (String) responseResultMap.get("code");
        // 业务成功/失败码
        String subCode = (String) responseResultMap.get("sub_code");
        // 订单号
        String orderNo = request.getOrderNo();

        TradeErrorCode tradeErrorCode = TradeErrorCode.fromCode(subCode);

        // 业务处理成功
        if (AlipayErrorCode.SUCCESS.getCode().equals(code)) {
            AlipayOrderStatusEnum status = AlipayOrderStatusEnum.fromCode(subCode);
            if (status == AlipayOrderStatusEnum.PAID || status == AlipayOrderStatusEnum.SUCCESS) {
                request.setStatus(ProcessStatus.SUCCESS.getCode());
                request.setPaidAt(LocalDateTime.now());
                updateById(request);
                log.info("订单[{}]支付成功，状态已更新为SUCCESS", request.getOrderNo());
            } else if (status == AlipayOrderStatusEnum.TIMEOUT_CLOSED
                    || status == AlipayOrderStatusEnum.CANCEL_CLOSED
                    || status == AlipayOrderStatusEnum.WAIT_PAY) {
                request.setStatus(ProcessStatus.FAILED.getCode());
                updateById(request);
                log.info("订单[{}]已关闭/未支付，状态已更新为FAILED", orderNo);
            } else {
                log.info("订单[{}]状态未变化，当前支付宝状态: {}", orderNo, status);
            }
        }

        // 业务处理失败
        if (AlipayErrorCode.BUSINESS_FAILED.getCode().equals(code)) {
            switch (Objects.requireNonNull(tradeErrorCode)) {

                // 系统错误,请稍后重试
                case SYSTEM_ERROR -> {
                    log.error("系统错误,订单错误{}", orderNo);
                    request.setStatus(ProcessStatus.FAILED.getCode());
                    updateById(request);
                }

                // 订单不存在
                case TRADE_NOT_EXIST -> {
                    log.warn("订单不存在: {}", orderNo);
                    // 可以标记订单状态为失败
                    request.setStatus(ProcessStatus.FAILED.getCode());
                    updateById(request);
                }

                // 无效参数
                case INVALID_PARAMETER -> {
                    log.warn("参数错误:,订单号{}", orderNo);
                    // 可以标记订单状态为失败
                    request.setStatus(ProcessStatus.FAILED.getCode());
                    updateById(request);
                }
            }
        }
    }


}
